from absl import app, flags
import datetime
import pandas as pd
import time

import coin.base.database.util as db_util
from xunkemgmt_client.tool.slack_noti import send_to_slack
from xunkemgmt.tool.strat_monitor.database.memcached_querier import MemcachedStrategySummaryQuerier

FLAGS = flags.FLAGS


def _formatNumber(x):
  if isinstance(x, int) or isinstance(x, float):
    return '%.2f%%' % (x * 100)
  else:
    return x


def check_monitor_value():
  db_config = db_util.read_db_config(FLAGS.memcached_config)
  querier = MemcachedStrategySummaryQuerier(db_config)
  strat_summary_messages = querier.query_strategy_summary_history()
  usd_rate_alarm_info = []
  fill_ratio_alarm_info = []
  for strat_summary_msg in strat_summary_messages:
    for strat_summary in strat_summary_msg.summaries:
      for quote in strat_summary.stat_per_quote:
        if not strat_summary.stat_per_quote[quote].HasField('pnl_mark_in_usd'):
          usd_rate_alarm_info.append(
              [strat_summary.strategy.strategy_group, strat_summary.strategy.strategy_name, quote])
      for account_id, account_stat in strat_summary.stat_per_account.items():
        for symbol, strat_stat in account_stat.stat_per_symbol.items():
          if strat_stat.HasField('fill_ratio_mark'):
            if strat_stat.fill_ratio_mark > 1 + FLAGS.threshold \
                or strat_stat.fill_ratio_mark < 0 - FLAGS.threshold:
              fill_ratio_alarm_info.append([
                  strat_summary.strategy.strategy_group,
                  strat_summary.strategy.strategy_name,
                  symbol,
                  strat_stat.fill_ratio_mark,
                  None
              ])
          if strat_stat.HasField('fill_ratio_4hr'):
            if strat_stat.fill_ratio_4hr > 1 + FLAGS.threshold \
                or strat_stat.fill_ratio_4hr < 0 - FLAGS.threshold:
              fill_ratio_alarm_info.append([
                  strat_summary.strategy.strategy_group,
                  strat_summary.strategy.strategy_name,
                  symbol,
                  None,
                  strat_stat.fill_ratio_4hr
              ])
  usd_rate_alarm_info = pd.DataFrame(usd_rate_alarm_info,
                                     columns=['strat_group', 'strat_name', 'quote'])
  fill_ratio_alarm_info = pd.DataFrame(
      fill_ratio_alarm_info,
      columns=['strat_group', 'strat_name', 'symbol', 'fill_ratio_mark', 'fill_ratio_4hr'])
  fill_ratio_alarm_info = fill_ratio_alarm_info[
      fill_ratio_alarm_info['strat_group'] != 'pass_unhedge']
  if len(fill_ratio_alarm_info) > 0:
    fill_ratio_alarm_info = \
        fill_ratio_alarm_info.groupby(
            ['strat_group', 'strat_name', 'symbol'])[['fill_ratio_mark', 'fill_ratio_4hr']].sum(
                dropna=False).reset_index()
    fill_ratio_alarm_info.replace({0: '-'}, inplace=True)
    fill_ratio_alarm_info['fill_ratio_mark'] = \
      fill_ratio_alarm_info['fill_ratio_mark'].apply(_formatNumber)
    fill_ratio_alarm_info['fill_ratio_4hr'] = \
      fill_ratio_alarm_info['fill_ratio_4hr'].apply(_formatNumber)
  return usd_rate_alarm_info, fill_ratio_alarm_info


def report_alarm_info(usd_rate_alarm_info, fill_ratio_alarm_info, ignore_list):
  fetched_dt = datetime.datetime.utcnow()
  if len(usd_rate_alarm_info) > 0:
    for i in usd_rate_alarm_info.index:
      index = usd_rate_alarm_info.loc[i, ['strat_group', 'strat_name', 'quote']].tolist()
      if index in ignore_list:
        usd_rate_alarm_info.loc[i] = None
      else:
        ignore_list.append(index)
    usd_rate_alarm_info.dropna(how='all', inplace=True)
    if len(usd_rate_alarm_info) > 0:
      alarm_title = "no usd rate alarm, fetched time: " + str(fetched_dt) + '\n'
      msg = "```" + alarm_title + usd_rate_alarm_info.to_string() + "```"
      send_to_slack(msg, 'coin_ops_monitor_test', 'msg')

  if len(fill_ratio_alarm_info) > 0:
    for i in fill_ratio_alarm_info.index:
      index = fill_ratio_alarm_info.loc[i, ['strat_group', 'strat_name', 'symbol']].tolist()
      if index in ignore_list:
        fill_ratio_alarm_info.loc[i] = None
      else:
        ignore_list.append(index)
    fill_ratio_alarm_info.dropna(how='all', inplace=True)
    if len(fill_ratio_alarm_info) > 0:
      alarm_title = "fill ratio alarm, fetched time: " + str(fetched_dt) + '\n'
      msg = "```" + alarm_title + fill_ratio_alarm_info.to_string() + "```"
      send_to_slack(msg, 'coin_ops_monitor_test', 'msg')
  return ignore_list


def main(_):
  ignore_list = []
  start_dt = datetime.datetime.now()
  while True:
    usd_rate_alarm_info, fill_ratio_alarm_info = check_monitor_value()
    ignore_list = report_alarm_info(usd_rate_alarm_info, fill_ratio_alarm_info, ignore_list)
    time.sleep(60)
    if datetime.datetime.now() - start_dt >= datetime.timedelta(seconds=FLAGS.duration):
      break


if __name__ == '__main__':
  flags.DEFINE_float('duration', 3600, 'sec')
  flags.DEFINE_float('threshold', 0, 'threshold')
  flags.DEFINE_string('memcached_config',
                      "../../coin_deploy/support_pta/config/memcached_config_iosg.json",
                      'path of database config.')
  app.run(main)
